package com.hooenergy.etl.starter.core;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class QueryHandler<E extends IQueryEntity> {

    @Autowired
    private QuerySupport reflectSupport;

    @SuppressWarnings("unchecked")
    private IQueryDao<E> getDao(Class<?> clsDao) {
        return (IQueryDao<E>) reflectSupport.getDao(clsDao);
    }


    /**
     * 获得数据总条数(关键字过滤)
     */
    private Long total(Class<?> clsDao, Map<String, Object> queryMap, Long start, Long end, String key) {
        return Optional.ofNullable(this.getDao(clsDao))
                .map(dao -> dao.total(queryMap, start, end, key))
                .orElse(null);
    }



    /**
     * 分页获得数据查询
     */
    private List<E> findSource(Class<?> clsDao, Map<String, Object> queryMap, Long start, Long end, String key, long offset, long pageSize) {
        return Optional.ofNullable(this.getDao(clsDao))
                .map(dao -> dao.find(queryMap, start, end, key, offset, pageSize))
                .orElse(null);
    }

    /**
     * 获得数据查询
     */
    private List<E> findSource(Class<?> clsDao, Map<String, Object> queryMap, Long start, Long end, String key) {
        return Optional.ofNullable(this.getDao(clsDao))
                .map(dao -> dao.find(queryMap, start, end, key))
                .orElse(null);
    }






    // 是否是热点时间范围
    private boolean isHotTimeRange(long queryStartTime, HotTime hotTime){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH,-hotTime.getValue());
        if(queryStartTime >  calendar.getTimeInMillis()){
            return true;
        }

        return false;
    }

    // 分页默认查询策略
    private List<E> defaultFind(AbsDataIndex dataIndex, Pageable pageable){
        QueryCriteria queryCriteria = dataIndex.getQueryCriteria();

        List<E> hotSource = this.findSource(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId(), pageable.getOffset(), pageable.getPageSize());

        if(hotSource.size() == pageable.getPageSize()){
            return hotSource;
        }

        // 热库获取数据不够，去冷库补充size
        if(hotSource.size() > 0 && hotSource.size() < pageable.getPageSize()){
            List<E> listUnion = new ArrayList<>(pageable.getPageSize());
            Long hotTotal = this.total(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
            /** 计算出冷库补充的size大小   例如：如果热库中有1008 条。 当前pageable.getOffset()为1000 size为10 热库只查询出8条
             * 则需要补充剩余条数： 计算方式：size = （pageable.getOffset() + pageable.getPageSize() - hotTotal）**/
            // 计算等到冷库的 page.size
            int size = (int) (pageable.getOffset() + pageable.getPageSize() - hotTotal);
            List<E> coldSource = this.findSource(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId(), 0, size);
            listUnion.addAll(hotSource);
            listUnion.addAll(coldSource);
            return listUnion;
        }

        if(hotSource.size() == 0){
            Long hotTotal = this.total(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
            // 计算等到冷库的查询 offset 起始值
            int offset = (int) (pageable.getOffset() - hotTotal);
            List<E> coldSource = this.findSource(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId(), offset, pageable.getPageSize());
            return coldSource;
        }

        return new ArrayList<>(0);
    }


    // 默认查询策略
    private List<E> defaultFind(AbsDataIndex dataIndex){
        QueryCriteria queryCriteria = dataIndex.getQueryCriteria();
        List<E> listUnion = new ArrayList<>();

        List<E> hotSource = this.findSource(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());

        List<E> coldSource = this.findSource(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());

        listUnion.addAll(hotSource);
        listUnion.addAll(coldSource);
        return listUnion;
    }



    // 检查非空判断
    private void check(AbsDataIndex dataIndex){
        if(dataIndex == null){
            throw new RuntimeException("AbsDataIndex not null");
        }

        if(StringUtils.isBlank(dataIndex.getBusinessId())){
            throw new RuntimeException("AbsDataIndex.businessId not null");
        }

        if(dataIndex.getQueryCriteria() == null){
            throw new RuntimeException("AbsDataIndex.queryCriteria not null");
        }
    }




    // 获取数据总数
    public long total(AbsDataIndex dataIndex){
        this.check(dataIndex);
        QueryCriteria queryCriteria = dataIndex.getQueryCriteria();

        if(dataIndex.getQueryCriteria().getStart() != null && dataIndex.getQueryCriteria().getEnd() != null) {
            Long hotTotal = this.total(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
            //获得数据总记录数
            long total = hotTotal;

            // 如果热点数据范围直接查询返回
            if(isHotTimeRange(queryCriteria.getStart(), dataIndex.getHotTime()) &&
                    isHotTimeRange(queryCriteria.getEnd(), dataIndex.getHotTime())){
                return total;
            }

            Long coldTotal = this.total(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
            total += coldTotal;

            return total;
        }


        Long hotTotal = this.total(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
        //获得数据总记录数
        long total = hotTotal;
        Long coldTotal = this.total(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
        total += coldTotal;
        return total;
    }



    // 分页获取数据
    public List<E> find(AbsDataIndex dataIndex, Pageable pageable) {
        this.check(dataIndex);

        if(dataIndex.getQueryCriteria().getStart() != null && dataIndex.getQueryCriteria().getEnd() != null) {
            // 返回的list 结果
            // 如果热点数据范围直接查询返回
            QueryCriteria queryCriteria = dataIndex.getQueryCriteria();
            if(isHotTimeRange(queryCriteria.getStart(), dataIndex.getHotTime()) &&
                    isHotTimeRange(queryCriteria.getEnd(), dataIndex.getHotTime())){
                List<E> hotSource = this.findSource(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                        queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId(), pageable.getOffset(), pageable.getPageSize());
                return hotSource;
            }

            // 如果开始时间在冷库范围，结束时间在热库数据范围
            if(!isHotTimeRange(queryCriteria.getStart(), dataIndex.getHotTime()) &&
                    isHotTimeRange(queryCriteria.getEnd(), dataIndex.getHotTime())){

                return defaultFind(dataIndex, pageable);
            }
            // 时间范围在冷库范围 获取冷库的数据
            List<E> coldSource = this.findSource(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId(), pageable.getOffset(), pageable.getPageSize());
            return coldSource;
        }

        return defaultFind(dataIndex, pageable);
    }


    // 获取所有数据
    public List<E> find(AbsDataIndex dataIndex) {
        this.check(dataIndex);

        if(dataIndex.getQueryCriteria().getStart() != null && dataIndex.getQueryCriteria().getEnd() != null) {
            // 返回的list 结果
            // 如果热点数据范围直接查询返回
            QueryCriteria queryCriteria = dataIndex.getQueryCriteria();
            if(isHotTimeRange(queryCriteria.getStart(), dataIndex.getHotTime()) &&
                    isHotTimeRange(queryCriteria.getEnd(), dataIndex.getHotTime())){
                List<E> hotSource = this.findSource(dataIndex.getHotDao(), queryCriteria.getQueryMap(),
                        queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
                return hotSource;
            }

            // 如果开始时间在冷库范围，结束时间在热库数据范围
            if(!isHotTimeRange(queryCriteria.getStart(), dataIndex.getHotTime()) &&
                    isHotTimeRange(queryCriteria.getEnd(), dataIndex.getHotTime())){

                return defaultFind(dataIndex);
            }
            // 时间范围在冷库范围 获取冷库的数据
            List<E> coldSource = this.findSource(dataIndex.getColdDao(), queryCriteria.getQueryMap(),
                    queryCriteria.getStart(), queryCriteria.getEnd(), dataIndex.getBusinessId());
            return coldSource;
        }

        return defaultFind(dataIndex);
    }









}
